package com.bawei.http

import android.os.Environment
import com.alibaba.android.arouter.launcher.ARouter
import com.bawei.base.constants.BaseConst
import com.bawei.base.path.RoutePath
import com.tencent.mmkv.MMKV
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import okhttp3.WebSocketListener
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.converter.gson.GsonConverterFactory
import org.json.JSONObject
import retrofit2.Retrofit
import java.io.File
import java.net.Proxy
import java.security.SecureRandom
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLHandshakeException
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager

/**
 * OKHttpClient管理类
 */
object OkHttpClientManager {

    /**
     * 普通Http请求客户端
     */
    val httpClientInstance: OkHttpClient by lazy {
        createOkHttpClient()
    }

    /**
     * 统一提供创建OKHttpClient的方法
     */
    fun createOkHttpClient(): OkHttpClient{
        var okBuilder = OkHttpClient.Builder().apply {
            //设置连接超时时间
            connectTimeout(BaseConst.CONNECT_TIME_OUT, TimeUnit.SECONDS)
            //设置读取超时时间
            readTimeout(BaseConst.READ_TIME_OUT, TimeUnit.SECONDS)
            //设置写入超时时间
            writeTimeout(BaseConst.WRITE_TIME_OUT, TimeUnit.SECONDS)

            //设置接口请求日志拦截器
            if (BuildConfig.isOpenLog){
                addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
            }

            //Header参数拦截器
            addInterceptor(getHeaderInterceptor())

            //服务器异常拦截器
            addInterceptor(getServiceExceptionInterceptor())

            //防止抓包软件获取接口数据
            proxy(Proxy.NO_PROXY)
        }
        return okBuilder.build()
    }

    /**
     * 普通Https请求客户端
     */
    val httpsClientInstance: OkHttpClient by lazy {
        createOkHttpsClient()
    }

    fun createOkHttpsClient(): OkHttpClient{
        var okBuilder = OkHttpClient.Builder().apply {
            //设置连接超时时间
            connectTimeout(BaseConst.CONNECT_TIME_OUT, TimeUnit.SECONDS)
            //设置读取超时时间
            readTimeout(BaseConst.READ_TIME_OUT, TimeUnit.SECONDS)
            //设置写入超时时间
            writeTimeout(BaseConst.WRITE_TIME_OUT, TimeUnit.SECONDS)

            //设置接口请求日志拦截器
            if (BuildConfig.isOpenLog){
                addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
            }

            //Header参数拦截器
            addInterceptor(getHeaderInterceptor())

            //服务器异常拦截器
            addInterceptor(getServiceExceptionInterceptor())

            //防止抓包软件获取接口数据
            proxy(Proxy.NO_PROXY)

            //设置支持的网络协议
            protocols(listOf(Protocol.HTTP_2))

            //添加Https支持
            sslSocketFactory(sslSocketFactory, trustManager)

            //设置缓存目录
            val cacheFile = getExternalStoreFile()
            if(cacheFile != null){
                cache(Cache(cacheFile, 10 * 1024 * 1024))
            }
        }
        return okBuilder.build()
    }

    /**
     * WebSocket请求客户端
     */
    private val webSocketInstance: OkHttpClient by lazy {
        var wsOKBuilder = OkHttpClient.Builder().apply {
            //设置心跳间隔时间, 维持长连接
            pingInterval(10, TimeUnit.SECONDS)
        }
        wsOKBuilder.build()
    }

    /**
     * 发起webSocket请求
     */
    fun createWebSocketRequest(webSocketUrl: String, listener: WebSocketListener){
        val requestBuilder = Request.Builder().apply {
            url(webSocketUrl)
        }
        webSocketInstance.newWebSocket(requestBuilder.build(), listener)
    }

    /**
     * Retrofit实例
     */
    val retrofitInstance: Retrofit by lazy {
        Retrofit.Builder().apply {
            baseUrl(BuildConfig.BASE_URL)
            client(httpClientInstance)
            addConverterFactory(GsonConverterFactory.create())
        }.build()
    }

    /**
     * 对外提供创建Retrofit实例的方法
     */
    fun createRetrofit(okHttpClient: OkHttpClient): Retrofit{
        return Retrofit.Builder().apply{
            baseUrl(BuildConfig.BASE_URL)
            client(okHttpClient)
            addConverterFactory(GsonConverterFactory.create())
        }.build()
    }


    private fun getExternalStoreFile(): File? {
        val externalStoreFile = Environment.getExternalStorageDirectory()
        if (externalStoreFile.exists()) return File(externalStoreFile, "park_network_cache")
        return null
    }


    private val sslSocketFactory: SSLSocketFactory
        get() = try{
            val sslContext = SSLContext.getInstance("SSL")
            sslContext.init(null, arrayOf(trustManager), SecureRandom())
            sslContext.socketFactory
        } catch (e: Exception) {
            throw RuntimeException(e)
        }

    private val trustManager: X509TrustManager
        get() = object : X509TrustManager {
            /**
             * 检查客户端的证书
             */
            override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) { }

            /**
             * 检查服务端的证书
             */
            override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
                //防止抓包工具，如Fiddler, Charles抓取数据
                chain?.forEach {certificate ->
                    if (certificate.issuerX500Principal.name.contains("Charles")||
                        certificate.issuerX500Principal.name.contains("Fiddler")){
                        throw SSLHandshakeException("Fiddler或Charles证书被拒绝")
                    }
                }
            }

            override fun getAcceptedIssuers(): Array<X509Certificate> {
                return arrayOf()
            }
        }

    /**
     * 请求头拦截器
     */
    private fun getHeaderInterceptor(): Interceptor {
        return object : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                //获取Token
                var token = MMKV.defaultMMKV().decodeString("token", "park_2208")
                var newBuilder = chain.request().newBuilder()
                if (token != null) {
                    newBuilder.header("token", token).build()
                }
                //获取AccessId
                var accessId = MMKV.defaultMMKV().decodeString("accessId", "")
                if (accessId != null) {
                    newBuilder.header("accessId", accessId).build()
                }
                //执行请求
                var newRequest = newBuilder.build()
                var response = chain.proceed(newRequest)

                //验证Token是否过期
                if (response.code == 403 || response.code == 401) {
                    ARouter.getInstance().build(RoutePath.PATH_LOGIN_PAGE).navigation()
                }

                return response
            }
        }
    }

    /**
     * 服务器异常拦截器
     * Interceptor属于责任链模式
     */
    private fun getServiceExceptionInterceptor(): Interceptor {
        return object : Interceptor {
            override fun intercept(chain: Interceptor.Chain): Response {
                var errorResponse = chain.proceed(chain.request())
                var responseBuilder = errorResponse.newBuilder()
                if(errorResponse.code == 500){
                    var newJson = JSONObject()
                    newJson.put("code", 500)
                    newJson.put("message", "服务器异常, 请联系客服！")
                    responseBuilder.body(newJson.toString().toResponseBody("application/json;charset=UTF-8".toMediaTypeOrNull()))
                }
                return responseBuilder.build()
            }
        }

    }

    fun clearAllRequest(){
        httpsClientInstance?.dispatcher?.run {
            cancelAll() //取消请求
            executorService.shutdown() //关闭线程池
        }

        httpsClientInstance?.dispatcher?.run {
            cancelAll() //取消请求
            executorService.shutdown() //关闭线程池
        }

        webSocketInstance?.dispatcher?.run {
            cancelAll() //取消请求
            executorService.shutdown() //关闭线程池
        }

        //关闭缓存
        httpClientInstance?.cache?.close()
        httpsClientInstance?.cache?.close()
        webSocketInstance?.cache?.close()
    }

}